package com.devmarvel.creditcardentry.fields;

import com.devmarvel.creditcardentry.internal.CreditCardFieldDelegate;
import com.devmarvel.creditcardentry.util.ResUtil;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.InputAttribute;
import ohos.agp.components.Text;
import ohos.agp.components.TextField;
import ohos.agp.components.element.Element;
import ohos.agp.utils.Color;
import ohos.agp.utils.TextAlignment;
import ohos.app.Context;
import ohos.multimodalinput.event.KeyEvent;

import java.lang.reflect.Field;

public abstract class CreditEntryFieldBase extends TextField implements
        Text.TextObserver, Component.KeyEventListener, Component.ClickedListener {

    protected static final int HORIZONTAL_PADDING = 20;
    protected static final int PADDING_OFFSET = 10;

    CreditCardFieldDelegate delegate;

    final Context context;

    String lastValue = null;
    String oldText = "";

    private boolean valid = false;
    public boolean watcherEnabled = false;

    // custom attributes
    private static final String default_text_colors = "default_text_colors";
    private static final String text_color = "text_color";
    private static final String hint_text_color = "hint_text_color";
    private static final String cursor_color = "cursor_color";

    public CreditEntryFieldBase(Context context) {
        super(context);
        this.context = context;
        init();
    }

    public CreditEntryFieldBase(Context context, AttrSet attrs) {
        super(context, attrs);
        this.context = context;
        init(attrs);
    }

    public CreditEntryFieldBase(Context context, AttrSet attrs, String defStyle) {
        super(context, attrs, defStyle);
        this.context = context;
        init(attrs);
    }

    void init() {
        init(null);
    }

	void init(AttrSet attrs) {
		setTextAlignment(TextAlignment.CENTER);
		setInputMethodOption(InputAttribute.ENTER_KEY_TYPE_UNSPECIFIED);
		setBackground(ResUtil.buildDrawableByColor(Color.TRANSPARENT.getValue()));
		setTextInputType(InputAttribute.PATTERN_NUMBER);
		addTextObserver(this);
        watcherEnabled = true;
		setKeyEventListener(this);
		setClickedListener(this);
		setPadding(HORIZONTAL_PADDING, 0, HORIZONTAL_PADDING, 0);

        setStyle(attrs);
    }

    void setStyle(AttrSet attrs) {
        if (attrs == null) {
            return;
        }

		// If default_text_colors is true, we will not set any text or cursor colors
		// and just use the defaults provided by the system / theme.
		if (!(attrs.getAttr(default_text_colors).isPresent() && attrs.getAttr(default_text_colors).get().getBoolValue())) {
            Color textColor = attrs.getAttr(text_color).isPresent() ?
                    attrs.getAttr(text_color).get().getColorValue() : Color.BLACK;
            Color hintTextColor = attrs.getAttr(hint_text_color).isPresent() ?
                    attrs.getAttr(hint_text_color).get().getColorValue() : Color.LTGRAY;
            Color cursorColor = attrs.getAttr(cursor_color).isPresent() ?
                    attrs.getAttr(cursor_color).get().getColorValue() : Color.BLACK;
			setTextColor(textColor);
			setHintColor(hintTextColor);
			setCursorDrawableColor(cursorColor.getValue());
		}
	}

    @Override
    public void onTextUpdated(String text, int start, int before, int count) {
        if (watcherEnabled) {
            beforeTextChanged(oldText, start, count, text.length());
            oldText = text;
            onTextChanged(text, start, before, count);
            afterTextChanged(text);
        }
    }

	public void onTextChanged(CharSequence s, int start, int before, int end) {
		if (start == 0 && before == 1 && s.length() == 0) {
			if (delegate != null) {
				delegate.focusOnPreviousField(this);
			}
		} else {
			String tmp = String.valueOf(s);
			if (!tmp.equals(lastValue)) {
				lastValue = tmp;
				textChanged(s, start, before, end);
			}
		}
	}

	public abstract void formatAndSetText(String updatedString);

    public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
    public void afterTextChanged(String s) {}

    public void textChanged(CharSequence s, int start, int before, int end) { }

	@Override
    public boolean onKeyEvent(Component component, KeyEvent keyEvent) {
        if (keyEvent.isKeyDown())
            return false;
        if (keyEvent.getKeyCode() == KeyEvent.KEY_ALT_LEFT
                || keyEvent.getKeyCode() == KeyEvent.KEY_ALT_RIGHT
                || keyEvent.getKeyCode() == KeyEvent.KEY_SHIFT_LEFT
                || keyEvent.getKeyCode() == KeyEvent.KEY_SHIFT_RIGHT)
            return false;
        if (keyEvent.getKeyCode() == KeyEvent.KEY_DEL
                && this.getText().length() == 0) {
            if (delegate != null) {
                delegate.focusOnPreviousField(this);
            }
        }
        return false;
    }

	@Override
	public void onClick(Component component) {
	}

	@SuppressWarnings("unused")
	public CreditCardFieldDelegate getDelegate() {
		return delegate;
	}

	public void setDelegate(CreditCardFieldDelegate delegate) {
		this.delegate = delegate;
	}

	public abstract void setHelperText(String helperText);

	public abstract String getHelperText();

	public boolean isValid() {
		return valid;
	}

	void setValid(boolean valid) {
		this.valid = valid;
	}

	private void backInput() {
		if (this.getText().toString().length() == 0) {
			if (delegate != null) {
				delegate.focusOnPreviousField(this);
			}
		}
	}

    public void setCursorDrawableColor(int color) {
        try {
            Field fCursorDrawableRes = Text.class.getDeclaredField("mCursorDrawableRes");
            fCursorDrawableRes.setAccessible(true);
            int mCursorDrawableRes = fCursorDrawableRes.getInt(this);
            Field fEditor = Text.class.getDeclaredField("mEditor");
            fEditor.setAccessible(true);
            Object editor = fEditor.get(this);
            Class<?> clazz = editor.getClass();
            Field fCursorDrawable = clazz.getDeclaredField("mCursorDrawable");
            fCursorDrawable.setAccessible(true);
            Element[] drawables = new Element[2];
            drawables[0] = ResUtil.getPixelMapDrawable(getContext(), mCursorDrawableRes);
            drawables[1] = ResUtil.getPixelMapDrawable(getContext(), mCursorDrawableRes);
            fCursorDrawable.set(editor, drawables);
        } catch (final Throwable ignored) {
            //
        }
    }

}
